/**
 *    Copyright 2012 Geensoft S.A.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/
package ar.com.greensoft.neo.dao.impl;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.envers.AuditReader;
import org.hibernate.envers.AuditReaderFactory;
import org.hibernate.envers.RevisionType;
import org.hibernate.envers.query.AuditEntity;
import org.hibernate.envers.query.AuditQuery;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import ar.com.greensoft.neo.architecture.Revision;
import ar.com.greensoft.neo.architecture.UsernameRevisionEntity;
import ar.com.greensoft.neo.dao.GenericWithRevisionDao;

/**
 * @author Jorge E. Villaverde
 *
 */
@Repository
@Transactional
public abstract class AbstractJpaWithRevisionDaoImpl<T> extends AbstractJpaDaoImpl<T> implements GenericWithRevisionDao<T, Long> {
	 
	protected AuditReader getAuditReader(){
		return AuditReaderFactory.get(entityManager);
	}
	
	@Override
	public long revisionCount() {
		throw new UnsupportedOperationException();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Revision<T>> allRevisions(Long id) {
		List<Revision<T>> ret = new ArrayList<Revision<T>>();
		AuditQuery query = getAuditReader().createQuery()
			    .forRevisionsOfEntity(getEntityClazz(), false, true)
			    .addOrder(AuditEntity.revisionNumber().desc())
			    .add(AuditEntity.id().eq(id));
		
		List<Object[]> results = query.getResultList();
		
		for(Object obj[] : results){
			T entity = (T)obj[0];
			UsernameRevisionEntity metada = (UsernameRevisionEntity)obj[1];
			RevisionType type = (RevisionType)obj[2];
			Number revisionNumber = metada.getId();
			
			Revision<T> revision = new Revision<T>(entity, revisionNumber, metada, type);
			ret.add(revision);			
		}
		
		return ret;
	}

	@Override
	public Revision<T> getRevision(Long id, Number revision) {
		T entity = getAuditReader().find(getEntityClazz(), id, revision);
		return new Revision<T>(entity, revision, null, null);
	}	
}
